
package net.qiqbframework.messaging;

import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Deque;
import java.util.LinkedList;
import java.util.NoSuchElementException;
import java.util.concurrent.Callable;

@Slf4j
public abstract class Scope {


    private static final ThreadLocal<Deque<Scope>> CURRENT_SCOPE = ThreadLocal.withInitial(LinkedList::new);


    @SuppressWarnings("unchecked")
    public static <S extends Scope> S getCurrentScope() throws IllegalStateException {
        try {
            return (S) CURRENT_SCOPE.get().getFirst();
        } catch (NoSuchElementException e) {
            throw new IllegalStateException("Cannot request current Scope if none is active");
        }
    }


    public static ScopeDescriptor describeCurrentScope() {
        return getCurrentScope().describeScope();
    }


    protected void startScope() {
        CURRENT_SCOPE.get().push(this);
    }


    protected void endScope() {
        Deque<Scope> scopes = CURRENT_SCOPE.get();
        if (this != scopes.peek()) {
            throw new IllegalStateException(
                    "Incorrectly trying to end another Scope then which the calling process is contained in."
            );
        }
        scopes.pop();

        if (scopes.isEmpty()) {
            log.debug("Clearing out ThreadLocal current Scope, as no Scopes are present");
            CURRENT_SCOPE.remove();
        }
    }

    protected <V> V executeWithResult(Callable<V> task) throws Exception {
        startScope();
        try {
            return task.call();
        } finally {
            endScope();
        }
    }

    public abstract ScopeDescriptor describeScope();
}
